using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading.Tasks;
using MauiApp.Models;

namespace MauiApp.Services
{

    /// <summary>
    /// 文件信息类，包含文件和用户相关信息
    /// </summary>
    public class FileInfo
    {
        public long FileId { get; set; }
        public string FileName { get; set; } = string.Empty;
        public string FileOwnerId { get; set; } = string.Empty;
        public string FilePath { get; set; } = string.Empty;
        public long FileSize { get; set; }
        public string FileType { get; set; } = string.Empty;
    }

    /// <summary>
    /// FTP上传凭证类，包含FTP服务器连接信息
    /// </summary>
    public class FtpUploadCredentials
    {
        public string FtpServerUrl { get; set; } = string.Empty;
        public string FtpUsername { get; set; } = string.Empty;
        public string FtpPassword { get; set; } = string.Empty;
        public string FtpDirectoryPath { get; set; } = string.Empty;
    }

    /// <summary>
    /// FTP上传服务类，用于处理文件上传到FTP服务器的相关功能
    /// </summary>
    public class FtpUploadService : BaseService
    {
        private readonly IApiService _apiService;
        private readonly HttpClient _httpClient;

        /// <summary>
        /// 构造函数，注入API服务
        /// </summary>
        /// <param name="apiService">API服务实例</param>
        public FtpUploadService(IApiService apiService)
        {
            _apiService = apiService;
            _httpClient = new HttpClient
            {
                BaseAddress = new Uri(ApiBaseUrl)
            };
        }

        /// <summary>
        /// 验证用户是否有权限进行上传
        /// </summary>
        /// <param name="uploadInfo">上传信息对象，包含文件和用户相关信息</param>
        /// <returns>包含FTP上传凭证的结果对象，如果验证失败则返回null</returns>
        public async Task<FtpUploadCredentials?> VerifyUploadPermissionAsync(MauiApp.Models.UploadInfo uploadInfo)
        {
            try
            {
                // 这里应该调用API服务来验证用户权限
                // 根据用户需求，只要数据库中有这个用户，就可以上传
                
                // 添加详细日志，追踪用户ID的设置情况
                LogHelper.Debug(string.Format("FtpUploadService.VerifyUploadPermissionAsync: 方法开始调用，传入的uploadInfo.UserId: {0}", uploadInfo.UserId));
                
                // 确保UploadInfo中的UserId使用App类中的静态全局用户信息
                App.LogCurrentUserInfo("FtpUploadService.VerifyUploadPermissionAsync");
                LogHelper.Info(string.Format("FtpUploadService: App.CurrentUserId的值: {0}", App.CurrentUserId));
                
                // 检查并设置UserId
                if (string.IsNullOrEmpty(App.CurrentUserId) )
                {
                    LogHelper.Warn("FtpUploadService: App.CurrentUserId为默认值或空，请检查用户登录状态！");
                }
                
                uploadInfo.UserId = App.CurrentUserId;
                LogHelper.Info(string.Format("FtpUploadService: 已设置uploadInfo.UserId = {0}", uploadInfo.UserId));
                
                // 获取认证令牌并设置认证头
                var authToken = _apiService.GetAuthToken();
                LogHelper.Debug(string.Format("FtpUploadService: 认证令牌是否为空: {0}", string.IsNullOrEmpty(authToken)));
                
                if (!string.IsNullOrEmpty(authToken))
                {
                    _httpClient.DefaultRequestHeaders.Authorization = 
                        new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", authToken);
                    LogHelper.Debug("FtpUploadService: 已设置Bearer认证头");
                }
                else
                {
                    LogHelper.Warn("FtpUploadService: 认证令牌为空，可能导致权限验证失败！");
                }
                
                // 调用后端接口进行权限验证
                LogHelper.Info(string.Format("FtpUploadService: 准备调用验证上传权限接口，参数: UserId={0}, FileName={1}", uploadInfo.UserId, uploadInfo.FileName));
                var response = await _httpClient.PostAsJsonAsync(
                    "file/verify-upload", uploadInfo);
                
                LogHelper.Info(string.Format("FtpUploadService: 验证上传权限接口响应状态码: {0}", response.StatusCode.ToString()));
                
                // 特别处理401错误
                if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
                {
                    LogHelper.Error("FtpUploadService: 验证上传权限失败 - 401未经授权！可能是用户ID无效或用户不存在");
                    if (response.Content != null)
                    {
                        var errorContent = await response.Content.ReadAsStringAsync();
                        LogHelper.Debug(string.Format("FtpUploadService: 401错误详情: {0}", errorContent));
                    }
                    else
                    {
                        LogHelper.Debug("FtpUploadService: 401错误，响应内容为空");
                    }
                    return null;
                }
                
                if (response.IsSuccessStatusCode)
                {
                    LogHelper.Info("FtpUploadService: 验证上传权限成功，准备读取凭证信息");
                    var credentials = await response.Content.ReadFromJsonAsync<FtpUploadCredentials>();
                    return credentials;
                }
                
                return null;
            }
            catch (Exception ex)
            {
                LogHelper.Error($"验证上传权限时出错: {ex.Message}");
                throw;
            }
        }

        /// <summary>
        /// 验证用户是否有权限进行下载
        /// </summary>
        /// <param name="fileInfo">文件信息对象，包含文件和用户相关信息</param>
        /// <returns>包含FTP下载凭证的结果对象，如果验证失败则返回null</returns>
        public async Task<FtpUploadCredentials?> VerifyDownloadPermissionAsync(FileInfo fileInfo)
        {
            try
            {
                // 确保FileInfo中的用户ID使用App类中的静态全局用户信息
                App.LogCurrentUserInfo("FtpUploadService.VerifyDownloadPermissionAsync");
                fileInfo.FileOwnerId = App.CurrentUserId;
                LogHelper.Info($"FtpUploadService: 确保FileOwnerId使用静态全局用户信息 - FileOwnerId: {fileInfo.FileOwnerId}");
                
                // 获取认证令牌并设置认证头
                var authToken = _apiService.GetAuthToken();
                if (!string.IsNullOrEmpty(authToken))
                {
                    _httpClient.DefaultRequestHeaders.Authorization = 
                        new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", authToken);
                }
                
                // 调用后端接口进行权限验证
                var response = await _httpClient.PostAsJsonAsync(
                    "file/verify-download", fileInfo);
                
                LogHelper.Info(string.Format("FtpUploadService: 验证下载权限接口响应状态码: {0}", response.StatusCode.ToString()));
                
                if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
                {
                    // 特别处理401错误
                    LogHelper.Error("FtpUploadService: 验证下载权限失败 - 401未经授权！可能是用户ID无效或用户不存在");
                    if (response.Content != null)
                    {
                        var errorContent = await response.Content.ReadAsStringAsync();
                        LogHelper.Debug(string.Format("FtpUploadService: 401错误详情: {0}", errorContent));
                    }
                    else
                    {
                        LogHelper.Debug("FtpUploadService: 401错误，响应内容为空");
                    }
                    return null;
                }
                
                if (response.IsSuccessStatusCode)
                {
                    LogHelper.Info("FtpUploadService: 验证上传权限成功，准备读取凭证信息");
                    var credentials = await response.Content.ReadFromJsonAsync<FtpUploadCredentials>();
                    return credentials;
                }
                
                return null;
            }
            catch (Exception ex)
            {
                LogHelper.Error($"验证下载权限时出错: {ex.Message}");
                throw;
            }
        }

        /// <summary>
        /// 在FTP服务器上创建目录
        /// </summary>
        /// <param name="credentials">FTP凭证</param>
        /// <param name="directoryPath">要创建的目录路径</param>
        /// <returns>目录是否创建成功</returns>
        private async Task<bool> CreateFtpDirectoryAsync(FtpUploadCredentials credentials, string directoryPath)
        {
            try
            {
                if (string.IsNullOrEmpty(directoryPath))
                {
                    LogHelper.Debug("目录路径为空，无需创建");
                    return true;
                }

                directoryPath = directoryPath.Replace('\\', '/');
                string[] directories = directoryPath.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
                string currentPath = string.Empty;
                
                foreach (string directory in directories)
                {
                    currentPath = currentPath == string.Empty ? directory : $"{currentPath}/{directory}";
                    string ftpCreateDirectoryUrl = $"{credentials.FtpServerUrl.TrimEnd('/')}/{currentPath}";
                    
                    try
                    {
                        FtpWebRequest request = (FtpWebRequest)WebRequest.Create(ftpCreateDirectoryUrl);
                        request.Method = WebRequestMethods.Ftp.MakeDirectory;
                        request.Credentials = new NetworkCredential(credentials.FtpUsername, credentials.FtpPassword);
                        request.UsePassive = true;
                        request.UseBinary = true;
                        request.Timeout = 60000;
                        
                        using (FtpWebResponse response = (FtpWebResponse)await request.GetResponseAsync())
                        {
                            LogHelper.Debug($"目录创建成功: {directory}");
                        }
                    }
                    catch (WebException webEx)
                    {
                        if (webEx.Response is FtpWebResponse ftpResponse && 
                            ftpResponse.StatusCode == FtpStatusCode.ActionNotTakenFileUnavailable)
                        {
                            LogHelper.Debug($"目录已存在: {directory}");
                            continue;
                        }
                        
                        LogHelper.Error($"创建FTP目录失败: {webEx.Message}");
                        return false;
                    }
                }
                
                return true;
            }
            catch (Exception ex)
            {
                LogHelper.Error($"创建FTP目录异常: {ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// 根据服务器返回的信息和权限，将文件上传到FTP服务器
        /// </summary>
        /// <param name="filePath">本地文件路径</param>
        /// <param name="credentials">FTP上传凭证</param>
        /// <param name="targetFileName">目标文件名（可选，如果不提供则使用原文件名）</param>
        /// <returns>上传是否成功</returns>
        public async Task<string> UploadFileToFtpAsync(string filePath, FtpUploadCredentials credentials)
        {
            string resultFileName = string.Empty;
            // 将fileName变量定义移到try块外，确保在catch块中也能访问
            string fileName = string.Empty;
            
            try
            {
                if (!File.Exists(filePath))
                {
                    throw new FileNotFoundException("要上传的文件不存在", filePath);
                }

                // 确定目标文件名，如果未提供则使用原文件名
                 fileName = Path.GetFileName(filePath);
                //string extension = Path.GetExtension(Path.GetFileName(filePath)).ToLower();
                //fileName =Guid.NewGuid().ToString() + extension;

                // 构建完整的FTP上传路径 - 改进路径构建逻辑，确保处理好各种路径分隔符
                string ftpDirectoryPath = credentials.FtpDirectoryPath.Trim('/').Trim('\\');
                string cleanServerUrl = credentials.FtpServerUrl.TrimEnd('/');
                // 确保路径包含文件名，这是上传文件操作必需的
                string ftpUploadUrl = $"{cleanServerUrl}/{ftpDirectoryPath}/{fileName}";
                
                // 替换路径中的反斜杠为正斜杠,好像没什么用
                ftpUploadUrl = ftpUploadUrl.Replace('\\', '/');
                
                LogHelper.Debug($"构建的FTP上传路径: {ftpUploadUrl}");
                LogHelper.Debug($"文件名: {fileName}");
                LogHelper.Debug($"凭证信息 - 用户名: {credentials.FtpUsername}, 密码长度: {credentials.FtpPassword?.Length ?? 0}");
                LogHelper.Debug($"目录路径: {credentials.FtpDirectoryPath}");
                LogHelper.Debug($"清理后的目录路径: {ftpDirectoryPath}");
                
                // 确保FTP服务器上的目标目录存在 - 解决FTP 550错误的关键
                LogHelper.Debug("开始创建FTP目录...");
                bool directoryCreated = await CreateFtpDirectoryAsync(credentials, ftpDirectoryPath);
                if (!directoryCreated)
                {
                    LogHelper.Error("创建FTP目录失败，无法继续上传");
                    return string.Empty;
                }
                LogHelper.Debug("FTP目录创建成功或已存在");

                // 创建FTP请求
                LogHelper.Debug($"创建FTP请求: {ftpUploadUrl}");
                LogHelper.Debug($"请求方法: {WebRequestMethods.Ftp.UploadFile}");
                FtpWebRequest request = (FtpWebRequest)WebRequest.Create(ftpUploadUrl);
                request.Method = WebRequestMethods.Ftp.UploadFile;
                request.Credentials = new NetworkCredential(credentials.FtpUsername, credentials.FtpPassword);
                request.UseBinary = true;
                request.UsePassive = true;
                request.KeepAlive = false;
                request.Timeout = 60000; // 设置超时时间为60秒
                request.ReadWriteTimeout = 60000;
              

                // 读取文件内容并上传
                using (FileStream fileStream = File.OpenRead(filePath))
                using (Stream requestStream = request.GetRequestStream())
                {
                    // 使用异步上传
                    await fileStream.CopyToAsync(requestStream);
                }

                // 获取响应
                using (FtpWebResponse response = (FtpWebResponse)await request.GetResponseAsync())
                {
                    LogHelper.Info($"文件上传成功: {response.StatusDescription}");
                    LogHelper.Info($"FTP状态码: {response.StatusCode}");
                    if( response.StatusCode == FtpStatusCode.ClosingData)
                    {
                        resultFileName  = $"{ftpDirectoryPath}/{fileName}";
                    }
                }
                return resultFileName;
            }
            catch (WebException webEx)
            {
                LogHelper.Error($"Web异常: {webEx.Message}");
                if (webEx.Response is FtpWebResponse ftpResponse)
                {
                    LogHelper.Error($"FTP错误状态码: {ftpResponse.StatusCode}");
                    LogHelper.Error($"FTP错误描述: {ftpResponse.StatusDescription}");
                    
                    // 针对常见FTP错误码添加专门的诊断信息
                    if (ftpResponse.StatusCode == FtpStatusCode.ActionNotTakenFileUnavailable)
                    {
                        LogHelper.Warn("[重要诊断] FTP 550错误: 文件或目录不可用。可能的原因：");
                        LogHelper.Warn("1. 目标目录不存在（需要先创建目录）");
                        LogHelper.Warn("2. 文件名或路径包含特殊字符");
                        LogHelper.Warn("3. 用户权限不足，无法在指定位置创建或写入文件");
                        LogHelper.Warn("4. FTP服务器配置限制");
                        LogHelper.Warn($"[详细路径信息] 服务器URL: {credentials.FtpServerUrl}");
                        LogHelper.Warn($"[详细路径信息] 目录路径: {credentials.FtpDirectoryPath}");
                        LogHelper.Warn($"[详细路径信息] 目标文件名: {fileName}");
                    }
                }
                if (webEx.InnerException != null)
                {
                    LogHelper.Error($"内部异常: {webEx.InnerException.Message}");
                }
                LogHelper.Error($"异常堆栈: {webEx.StackTrace}");
                // 不使用throw，而是返回false表示上传失败
                return string.Empty;
            }
            catch (Exception ex)
            {
                LogHelper.Error($"上传文件到FTP服务器时出错: {ex.Message}");
                if (ex.InnerException != null)
                {
                    LogHelper.Error($"内部异常: {ex.InnerException.Message}");
                }
                LogHelper.Error($"异常堆栈: {ex.StackTrace}");
                // 不使用throw，而是返回false表示上传失败
                return string.Empty;
            }
        }

        /// <summary>
        /// 根据服务器返回的信息和权限，从FTP服务器下载文件
        /// </summary>
        /// <param name="ftpRelativePath">FTP上的文件相对路径</param>
        /// <param name="localFilePath">本地文件保存路径</param>
        /// <param name="credentials">FTP下载凭证</param>
        /// <returns>下载是否成功</returns>
        public async Task<bool> DownloadFileFromFtpAsync(string ftpRelativePath, string localFilePath, FtpUploadCredentials credentials)
        {
            try
            {
                // 确保本地目录存在
                string directory = Path.GetDirectoryName(localFilePath);
                if (!Directory.Exists(directory))
                {
                    Directory.CreateDirectory(directory);
                }

                // 构建完整的FTP下载路径
                string cleanServerUrl = credentials.FtpServerUrl.TrimEnd('/');
                string cleanRelativePath = ftpRelativePath.TrimStart('/');
                string ftpDownloadUrl = $"{cleanServerUrl}/{cleanRelativePath}";

                // 创建FTP请求
                FtpWebRequest request = (FtpWebRequest)WebRequest.Create(ftpDownloadUrl);
                request.Method = WebRequestMethods.Ftp.DownloadFile;
                request.Credentials = new NetworkCredential(credentials.FtpUsername, credentials.FtpPassword);
                request.UseBinary = true;
                request.UsePassive = true;
                request.KeepAlive = false;

                // 获取响应并下载文件
                using (FtpWebResponse response = (FtpWebResponse)await request.GetResponseAsync())
                using (Stream responseStream = response.GetResponseStream())
                using (FileStream fileStream = File.Create(localFilePath))
                {
                    if (responseStream != null)
                    {
                        await responseStream.CopyToAsync(fileStream);
                    }
                    
                    LogHelper.Info($"文件下载成功: {response.StatusDescription}");
                    return response.StatusCode == FtpStatusCode.ClosingData;
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error($"从FTP服务器下载文件时出错: {ex.Message}");
                throw;
            }
        }
    }
}